package Buildings;
import Buildings.dwelling.*;
import Buildings.office.*;
import Buildings.dwelling.hotel.*;
import Interfaces.*;
import java.io.*;
import java.util.*;
import java.lang.reflect.*;

public class Buildings {
    
   // private static int []buildingsTable=new int[]{1,2,3};//1-жилой,2-офис,3-отель
    private static BuildingFactory x=new DwellingFactory();
    public static void setBuildingFactory(BuildingFactory y){
        x=y;
    }
    
    public static Space createSpace(double area){
        try{
        Class s=Class.forName(x.getClass().getName());
        //Class sx=x.getClass(); тоже самое
        Method m=s.getMethod("createSpace", new Class [] {Double.TYPE});
        Object res=m.invoke(x, area);
        return (Space)res;
        } catch (ClassNotFoundException ex) {
        } catch (NoSuchMethodException ex) {
        } catch (SecurityException ex) {
        } catch (IllegalAccessException ex) {
        } catch (IllegalArgumentException ex) {
        } catch (InvocationTargetException ex) {
        }
        return null;
    }
    public static Space createSpace(int rooms,double area){
        try{
        Class s=Class.forName(x.getClass().getName());
        //Class sx=x.getClass(); тоже самое
        Method m=s.getMethod("createSpace", new Class [] {Integer.TYPE,Double.TYPE});
        Object res=m.invoke(x, rooms,area);
        return (Space)res;
        } catch (ClassNotFoundException ex) {
        } catch (NoSuchMethodException ex) {
        } catch (SecurityException ex) {
        } catch (IllegalAccessException ex) {
        } catch (IllegalArgumentException ex) {
        } catch (InvocationTargetException ex) {
        }
        return null;
    }
    
    public static Floor createFloor(int spaces){
        try{
        Class s=Class.forName(x.getClass().getName());
        //Class sx=x.getClass(); тоже самое
        Method m=s.getMethod("createFloor", new Class [] {Integer.TYPE});
        Object res=m.invoke(x, spaces);
        return (Floor)res;
        } catch (ClassNotFoundException ex) {
        } catch (NoSuchMethodException ex) {
        } catch (SecurityException ex) {
        } catch (IllegalAccessException ex) {
        } catch (IllegalArgumentException ex) {
        } catch (InvocationTargetException ex) {
        }
        return null;
    }
    public static Floor createFloor(Space ... spaces){
        try{
        Class s=Class.forName(x.getClass().getName());
        //Class sx=x.getClass(); тоже самое
        Method m=s.getMethod("createFloor", new Class [] {spaces.getClass()});
        Object res=m.invoke(x, (Object)spaces);
        return (Floor)res;
        } catch (ClassNotFoundException ex) {
        } catch (NoSuchMethodException ex) {
        } catch (SecurityException ex) {
        } catch (IllegalAccessException ex) {
        } catch (IllegalArgumentException ex) {
        } catch (InvocationTargetException ex) {
        }
        return null;
    }
    
    public static Building createBuilding(int floorsCount,int ...spaces){
        try{
        Class s=Class.forName(x.getClass().getName());
        //Class sx=x.getClass(); тоже самое
        Method m=s.getMethod("createFloor", new Class [] {Integer.TYPE,Integer.TYPE});
        Object res=m.invoke(x, floorsCount,spaces);
        return (Building)res;
        } catch (ClassNotFoundException ex) {
        } catch (NoSuchMethodException ex) {
        } catch (SecurityException ex) {
        } catch (IllegalAccessException ex) {
        } catch (IllegalArgumentException ex) {
        } catch (InvocationTargetException ex) {
        }
        return null;
    }
    public static Building createBuilding(Floor ...floors){
        try{
        Class s=Class.forName(x.getClass().getName());
        //Class sx=x.getClass(); тоже самое
        Method m=s.getMethod("createFloor", new Class [] {floors.getClass()});
        Object res=m.invoke(x, (Object)floors);
        return (Building)res;
        } catch (ClassNotFoundException ex) {
        } catch (NoSuchMethodException ex) {
        } catch (SecurityException ex) {
        } catch (IllegalAccessException ex) {
        } catch (IllegalArgumentException ex) {
        } catch (InvocationTargetException ex) {
        }
        return null;
    }
    
    /*
    public static Space createSpace(double area){
        return x.createSpace(area);
    }
    public static Space createSpace(int rooms,double area){
        return x.createSpace(rooms,area);
    }
    public static Floor createFloor(int spaces){
        return x.createFloor(spaces);
    }
    public static Floor createFloor(Space ... spaces){
        return x.createFloor(spaces);
    }
    public static Building createBuilding(int floorsCount,int ...spaces){
        return x.createBuilding(floorsCount, spaces);
    }
    public static Building createBuilding(Floor ...floors){
        return x.createBuilding(floors);
    }*/
    
    public static Floor synchronizedFloor(Floor floor){
        return new SynchronizedFloor(floor);
    }
    //байтовый поток
    public static void outputBuilding(Building b,OutputStream out)throws IOException{
        DataOutputStream DOS=new DataOutputStream(out);
        
        DOS.writeInt(b.getHowMuchFloorInBuilding());//всего этажей
        for(int i=0;i<b.getHowMuchFloorInBuilding();i++){
            Floor fl=b.getFloor(i);
            DOS.writeInt(fl.getHowMuchSpaceInFloor());//сколько помещений на этаже
            for(int j=0;j<fl.getHowMuchSpaceInFloor();j++){
                DOS.writeInt(b.getFloor(i).getSpaceInFloor(j).getHowMuchRooms());//кол-во комнат
                DOS.writeDouble(b.getFloor(i).getSpaceInFloor(j).getHowMuchArea());//площадь 
            }
        }      
    }
    public static Building inputBuilding(InputStream in)throws IOException{
        int howMuchFloor;
        DataInputStream DIS=new DataInputStream(in);
        howMuchFloor=DIS.readInt();//чтение сколько этажей
        Floor []Fl=new Floor[howMuchFloor];
        for(int i=0;i<howMuchFloor;i++){
            int howMuchSpace=DIS.readInt();//чтение кол-ва помещений на этаже
            Fl[i]=createFloor(howMuchSpace);
            for(int j=0;j<howMuchSpace;j++){
                Space s=createSpace(DIS.readInt(),DIS.readDouble());
                Fl[i].setSpaceInFloor(j,s);
            }  
        }
        Building b=createBuilding(Fl);
        return b;
    }
    //символьный поток
    public static void writeBuilding(Building b,Writer out)throws IOException{
        PrintWriter SW=new PrintWriter(out);
        Formatter fmt = new Formatter();
        fmt.format("%d", b.getHowMuchFloorInBuilding());
        fmt.flush();
        //SW.print(b.getHowMuchFloorInBuilding());//всего этажей
        //SW.print(" ");
        for(int i=0;i<b.getHowMuchFloorInBuilding();i++){
            //b.getFloor(i);
            //SW.print(b.getFloor(i).getHowMuchSpaceInFloor());//сколько помещений на этаже
            //SW.print(" ");
            fmt.format(" %d", b.getFloor(i).getHowMuchSpaceInFloor());
            fmt.flush();
            for(int j=0;j<b.getFloor(i).getHowMuchSpaceInFloor();j++){
                fmt.format(" %d %5.2f",b.getFloor(i).getSpaceInFloor(j).getHowMuchRooms(),b.getFloor(i).getSpaceInFloor(j).getHowMuchArea());
                fmt.flush();
                //SW.print(b.getFloor(i).getSpaceInFloor(j).getHowMuchRooms());//кол-во комнат и площадь помещения
                //SW.print(" ");
                //SW.print((int)b.getFloor(i).getSpaceInFloor(j).getHowMuchArea());
                //SW.print(" ");
            }
        }
        SW.print(fmt.format(" \n").toString());
        fmt.close();
        
        /*без форматирования
        PrintWriter SW=new PrintWriter(out);
        fmt.format(" %d", b.getHowMuchFloorInBuilding());
        //для чтения без токенайзера, вместо SW.print(b и " ") необходимо чтение по строкам
        SW.print(b.getHowMuchFloorInBuilding());//всего этажей
        SW.print(" ");
        for(int i=0;i<b.getHowMuchFloorInBuilding();i++){
            b.getFloor(i);
            SW.print(b.getFloor(i).getHowMuchSpaceInFloor());//сколько помещений на этаже
            SW.print(" ");
            for(int j=0;j<b.getFloor(i).getHowMuchSpaceInFloor();j++){
                SW.print(b.getFloor(i).getSpaceInFloor(j).getHowMuchRooms());//кол-во комнат и площадь помещения
                SW.print(" ");
                SW.print((int)b.getFloor(i).getSpaceInFloor(j).getHowMuchArea());
                SW.print(" ");
            }
        }
        SW.println("");*/
    }
    public static Building readBuilding(Reader in)throws IOException{
        //с использованием токенайзера
       StreamTokenizer z=new StreamTokenizer(in);
       z.nextToken();
       int howMuchFloor=(int)z.nval;
       
       if(howMuchFloor==0)throw new IOException();
       
        Floor []Fl=new Floor[howMuchFloor];
        for(int i=0;i<howMuchFloor;i++){
            z.nextToken();
            int howMuchSpace=(int)z.nval;//чтение кол-ва помещений на этаже
            Fl[i]=createFloor(howMuchSpace);
            for(int j=0;j<howMuchSpace;j++){
                z.nextToken();
                int rooms=(int)z.nval;
                z.nextToken();
                double area=z.nval;
                Space s=createSpace(rooms, area);
                Fl[i].setSpaceInFloor(j,s);
            }  
        }
        //Связан на конкретном классе, тк абстрактный от интерфейса объект нельзя создать
        Building b=createBuilding(Fl);
        return b;
    }
    
    //перегруженные методы
    public static Building readBuilding(Scanner sc)throws IOException
    {
        int howMuchFloor=sc.nextInt();
        Floor []Fl=new Floor[howMuchFloor];
        if(howMuchFloor==0)throw new IOException();
        
        int howMuchSpace,room=0;
        double area=0;
        
        for(int i=0;i<howMuchFloor;i++){
            if(sc.hasNextInt()){
                howMuchSpace=sc.nextInt();
                Fl[i]=createFloor(howMuchSpace);
                for(int j=0;j<howMuchSpace;j++){
                    if(sc.hasNextInt())room=sc.nextInt();
                    if(sc.hasNextDouble())area=sc.nextDouble();
                    Space s=createSpace(room, area);
                    Fl[i].setSpaceInFloor(j,s);
                }  
            }else return null;
        }
        Building b=createBuilding(Fl);
        return b;
    }
}
